package cn.edu.swu.cly.miniwebsvr.core;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Server {               // 作用：接收请求，传递给congig；传递http协议给HttpParser
    private final Config config = Config.getInstance();
    private final ExecutorService threadPool = Executors.newFixedThreadPool(10);        //固定线程池，可以有10个线程

    private void shutdownThreadPool() {
        threadPool.shutdown();
        try {
            if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
                threadPool.shutdownNow();
                if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
                    System.err.println("线程池未能完全关闭");
                }
            }
        } catch (InterruptedException e) {
            threadPool.shutdownNow();
        }
    }

    public void start() {
        // TODO: 222024321072039/蔡礼洋 实现ServerSocket的创建和监听
        try (ServerSocket serverSocket = new ServerSocket(config.getPort())) {
            System.out.println("MiniWebSvr 启动成功，监听端口：" + config.getPort());

            while (true) {          //Socket是编程接口，用于通讯
                Socket clientSocket = serverSocket.accept();
                System.out.println("接收到新的连接：" + clientSocket.getInetAddress());
                threadPool.execute(new RequestProcessor(clientSocket));
            }
        } catch (IOException e) {
            System.err.println("服务器启动失败或运行异常: " + e.getMessage());
            shutdownThreadPool();
        }
    }

    private static class RequestProcessor implements Runnable {
        private final Socket socket;

        public RequestProcessor(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            // TODO: 222024321072039/蔡礼洋 完善请求处理流程，确保异常安全和资源关闭
            InputStream inputStream = null;
            OutputStream outputStream = null;

            try {
                inputStream = socket.getInputStream();
                outputStream = socket.getOutputStream();

                Parameter request = HttpParser.parse(inputStream);

                Router router = new Router();
                router.route(request, outputStream);

            } catch (Exception e) {
                System.err.println("请求处理异常: " + e.getMessage());
                // TODO: 222024321072039/蔡礼洋 可以在这里实现返回 500 错误页面的逻辑
                try {
                    if (outputStream != null) {             //如果有输出
                        //构造符合http协议的返回500错误规范
                        String error500 = "HTTP/1.1 500 Internal Server Error\r\n" +
                                "Content-Type: text/html; charset=UTF-8\r\n" +
                                "Connection: close\r\n" +
                                "\r\n" +
                                "<html><body><h1>500 Internal Server Error</h1>" +
                                "<p>服务器处理请求时发生错误</p></body></html>";
                        outputStream.write(error500.getBytes(StandardCharsets.UTF_8));
                        outputStream.flush();       //确保发出，而不在缓存区

                    }
                } catch (IOException ex) {
                    System.err.println("发送500错误响应失败: " + ex.getMessage());
                }
            } finally {
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (IOException exception) {
                    System.err.println("关闭输入流失败：" + exception.getMessage());
                }
                try {
                    if (outputStream != null) {
                        outputStream.close();
                    }
                } catch (IOException e) {
                    System.err.println("关闭输出流失败：" + e.getMessage());
                }

                try {
                    if (socket != null && !socket.isClosed()) socket.close();
                } catch (IOException e) { /* ignore */ }
            }
        }
    }
}
